Let’s check out the data!
library(readr)
amazon <- read_csv("amazon_jobs_dataset.csv")
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
X1 = col_integer(),
Title = col_character(),
location = col_character(),
Posting_date = col_character(),
DESCRIPTION = col_character(),
`BASIC QUALIFICATIONS` = col_character(),
`PREFERRED QUALIFICATIONS` = col_character()
)
head(amazon)
Questions that we can focus on: - What are the popular locations of job openings? - Are there certain months when job opening are more? - How many jobs are posted every year? - How many jobs are posted every month? - What are most popular job titles? - What are minimum educational qualifications? - Which job requires higher degree? - What languages are required for jobs? - How many years of experience is required? - Which job categories require more experience? - Word clouds of preferred qualifications - Word clouds of Basic Qualifications - Word clouds of JOb description
dim(amazon)
[1] 3493 7
unique(amazon$Posting_date)[1:20]
[1] "March 1, 2018" "February 28, 2018" "February 27, 2018" "February 26, 2018" "February 25, 2018"
[6] "February 24, 2018" "February 23, 2018" "February 22, 2018" "February 21, 2018" "February 20, 2018"
[11] "February 19, 2018" "February 18, 2018" "February 16, 2018" "February 15, 2018" "February 14, 2018"
[16] "February 13, 2018" "February 12, 2018" "February 11, 2018" "February 9, 2018" "February 8, 2018"
We see that in some dates, there are multiple spaces between month and day. Let’s split it to year month and day.
library(stringr)
amazon$posting_month <- str_extract(amazon$Posting_date , "([A-Za-z]+)")
amazon$posting_day <- str_extract(amazon$Posting_date , "([0-9]+)")
amazon$posting_year <- str_extract(amazon$Posting_date, "([0-9]{4})")
unique(amazon$posting_month)
[1] "March" "February" "January" "December" "November" "October" "September" "August" "July"
[10] "June" "May" "April"
unique(amazon$posting_day)
[1] "1" "28" "27" "26" "25" "24" "23" "22" "21" "20" "19" "18" "16" "15" "14" "13" "12" "11" "9" "8" "7" "6"
[23] "5" "4" "3" "2" "31" "30" "29" "17" "10"
unique(amazon$posting_year)
[1] "2018" "2017" "2016" "2015" "2014" "2013" "2012" "2011"
Let’s also extract the countries from location column.
amazon$country <- str_extract(amazon$location, "[A-Za-z]+")
unique(amazon$country)
[1] "US" "IN" "RO" "CA" "DE" "PL" "AE" "ES" "IT" "IL" "UK" "ZA" "SG" "AU" "IE" "FR" "BR" "CN" "MX" "NL" "JO" "TW"
[23] "LU" "JP" NA
unique(amazon$location)
[1] "US, WA, Seattle" "IN, KA, Bangalore" "US, CA, Cupertino" "RO, Ia<U+015F>i"
[5] "US, CA, East Palo Alto" "US, CA, Santa Monica" "US, CA, Sunnyvale" "US, CA, Palo Alto"
[9] "US, MA, Boston" "US, MA, Cambridge" "CA, BC, Vancouver" "US, TX, Austin"
[13] "IN, TS, Hyderabad" "US, CA, San Francisco" "DE, BY, Munich" "RO, Iasi"
[17] "PL, Gdansk" "PL, Bielany Wroclawskie" "DE, Berlin" "US, CA, Irvine"
[21] "CA, ON, Toronto" "US, MA, North Reading" "US, MN, Minneapolis" "AE, Dubai"
[25] "US, CA, San Diego" "US, CA, Santa Barbara" "US, OR, Portland" "ES, Madrid"
[29] "IT, Vercelli" "US, NJ, Newark" "US, NY, New York" "IN, TN, Chennai"
[33] "IL, Herzliya" "DE, Aachen" "US, MA, Westborough" "US, VA, Herndon"
[37] "US, WA, Bellevue" "UK, London" "ZA, Cape Town" "US, MA, Andover"
[41] "US, CO, Boulder" "US, CA, Santa Cruz" "US, CA, San Luis Obispo" "UK, Cambridge"
[45] "SG, Singapore" "AU, NSW, Sydney" "IE, DUBLIN, Dublin" "US, CO, Broomfield"
[49] "FR, Paris" "US, Virtual" "UK, Edinburgh" "US, AZ, Tempe"
[53] "IL, Haifa" "BR, SP, Sao Paulo" "IN, DL, Gurgaon" "IN, HR, Gurgaon"
[57] "CN, Beijing" "MX, EMEX, Mexico City" "NL, The Hague" "US, VA, Ballston"
[61] "IT, MI, Milan" "JO, Amman" "CA, MB, Winnipeg" "US, PA, Pittsburgh"
[65] "CN, Shenzhen" "US, GA, Atlanta" "UK, N YORK, Heslington" "US, NJ, Jersey City"
[69] "TW, TP, Taipei" "US, CO, Denver" "DE, BY, Graben" "CN, Shanghai"
[73] "RO, Bucharest" "DE, SN, Dresden" "LU, Luxembourg" "DE, Standortuebergreifend"
[77] "US, CA, Foster City" "UK, CAMBS, Cambridge" "IL, Hod Hasharon" "JP, Meguro"
[81] "IT, AT, Asti" "IL," "UK, BRIST, Bristol" "CA, ON,"
[85] "IN, MH, Pune" "US, CA, San Jose" "CA," "CA, ON, Ottawa"
[89] NA "US, NV, Las Vegas"
amazon$city <- word(amazon$location, -1)
unique(amazon$city)
[1] "Seattle" "Bangalore" "Cupertino" "Ia<U+015F>i"
[5] "Alto" "Monica" "Sunnyvale" "Boston"
[9] "Cambridge" "Vancouver" "Austin" "Hyderabad"
[13] "Francisco" "Munich" "Iasi" "Gdansk"
[17] "Wroclawskie" "Berlin" "Irvine" "Toronto"
[21] "Reading" "Minneapolis" "Dubai" "Diego"
[25] "Barbara" "Portland" "Madrid" "Vercelli"
[29] "Newark" "York" "Chennai" "Herzliya"
[33] "Aachen" "Westborough" "Herndon" "Bellevue"
[37] "London" "Town" "Andover" "Boulder"
[41] "Cruz" "Obispo" "Singapore" "Sydney"
[45] "Dublin" "Broomfield" "Paris" "Virtual"
[49] "Edinburgh" "Tempe" "Haifa" "Paulo"
[53] "Gurgaon" "Beijing" "City" "Hague"
[57] "Ballston" "Milan" "Amman" "Winnipeg"
[61] "Pittsburgh" "Shenzhen" "Atlanta" "Heslington"
[65] "Taipei" "Denver" "Graben" "Shanghai"
[69] "Bucharest" "Dresden" "Luxembourg" "Standortuebergreifend"
[73] "Hasharon" "Meguro" "Asti" "IL,"
[77] "Bristol" "ON," "Pune" "Jose"
[81] "CA," "Ottawa" NA "Vegas"
Let us correct the city names that have multiple words.
amazon$city <- gsub(pattern = "Alto", replacement = "East Palo Alto", amazon$city)
amazon$city <- gsub(pattern = "Ia<U+015F>i", replacement = "Iasi", amazon$city)
amazon$city <- gsub(pattern = "Monica", replacement = "Santa Monica", amazon$city)
amazon$city <- gsub(pattern = "Francisco", replacement = "San Francisco", amazon$city)
amazon$city <- gsub(pattern = "Wroclawskie", replacement = "Bielany Wroclawskie", amazon$city)
amazon$city <- gsub(pattern = "Diego", replacement = "San Diego", amazon$city)
amazon$city <- gsub(pattern = "Barbara", replacement = "Santa Barbara", amazon$city)
amazon$city <- gsub(pattern = "York", replacement = "New York", amazon$city)
amazon$city <- gsub(pattern = "Town", replacement = "Cape Town", amazon$city)
amazon$city <- gsub(pattern = "Cruz", replacement = "Santa Cruz", amazon$city)
amazon$city <- gsub(pattern = "Obispo", replacement = "San Luis Obispo", amazon$city)
amazon$city <- gsub(pattern = "Paulo", replacement = "Sao Paulo", amazon$city)
amazon$city <- gsub(pattern = "Hasharon", replacement = "Hod Hasharon", amazon$city)
amazon$city <- gsub(pattern = "IL,", replacement = "Hod Hasharon", amazon$city)
amazon$city <- gsub(pattern = "On,", replacement = "Ottawa", amazon$city)
amazon$city <- gsub(pattern = "Jose", replacement = "San Jose", amazon$city)
amazon$city <- gsub(pattern = "CA,", replacement = "Ottawa", amazon$city)
amazon$city <- gsub(pattern = "Vegas", replacement = "Las Vegas", amazon$city)
The word “City” has been used with three different cities, so include them.
amazon$city <- ifelse(amazon$location == "US, CA, Foster City", "Foster City", amazon$city)
amazon$city <- ifelse(amazon$location == "MX, EMEX, Mexico City", "Mexico City", amazon$city)
amazon$city <- ifelse(amazon$location == "US, NJ, Jersey City", "Jersey City", amazon$city)
head(amazon)
What are most popular locations of Job Openings?
library(dplyr)
Attaching package: 'dplyr'
The following objects are masked from 'package:plyr':
arrange, count, desc, failwith, id, mutate, rename, summarise, summarize
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
location <- amazon[, c("country", "city")]
loc1 <- as.data.frame(table(location$city))
colnames(loc1) <- c("city", "Freq")
loc1 <- merge(loc1,location,by="city")
loc1 <- arrange(loc1, desc(Freq))
loc1 <- loc1 %>% distinct(city, .keep_all = TRUE)
loc1
Loading required package: lattice


Distribution of Jobs in all countries except US
p3 <- ggplot(filter(loc1,loc1$country!="US"), aes(x=factor(country), y=Freq, fill = factor(country))) +
geom_boxplot()
p3

Distribution of jobs in US
p4 <- ggplot(data = filter(loc1, loc1$country == "US"), aes(city, Freq, fill = city)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Jobs in US") +
coord_flip() +
guides(fill=FALSE) +
tilt_theme
p4

Analysis of Job Posting Date
How many jobs are posted every year and every month? Is there a certain period of year when jobs are posted more fequently?
amazon$Posting_date <- paste(amazon$posting_year, amazon$posting_month, amazon$posting_day,sep="-")
amazon$Posting_date <- as.Date(strptime(amazon$Posting_date,format="%Y-%b-%d"))
#amazon$Posting_date$zone <- NULL
(amazon$Posting_date[1:10])
[1] "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01" "2018-03-01"
[9] "2018-03-01" "2018-03-01"
#get day of the week based on date
dow <- function(x) format(as.Date(x), "%A")
amazon$weekday <- dow(amazon$Posting_date)
amazon$weekday[1:20]
[1] "Thursday" "Thursday" "Thursday" "Thursday" "Thursday" "Thursday" "Thursday" "Thursday" "Thursday"
[10] "Thursday" "Thursday" "Thursday" "Thursday" "Wednesday" "Wednesday" "Wednesday" "Wednesday" "Wednesday"
[19] "Wednesday" "Wednesday"
posting_date <- amazon[,c("posting_month", "posting_year", "weekday", "Posting_date")]
head(posting_date)
year <- as.data.frame(table(posting_date$posting_year))
colnames(year) <- c("Year", "Freq")
p5 <- ggplot(data = year, aes(Year, Freq, fill = Year)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Jobs postings by Year") +
guides(fill=FALSE) +
tilt_theme
p5

mon <- as.data.frame(table(posting_date$posting_month))
colnames(mon) <- c("Mon", "Freq")
lev = c("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December")
mon$Month <- factor(mon$Mon, lev)
p6 <- ggplot(data = mon, aes(Month, Freq, fill = Month)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Jobs postings by Month") +
guides(fill=FALSE) +
tilt_theme
p6

jday <- as.data.frame(table(posting_date$weekday))
colnames(jday) <- c("wd", "Freq")
lev <- c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
jday$weekday <- factor(jday$wd, lev)
p7 <- ggplot(data = jday, aes(weekday, Freq, fill = weekday)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Jobs postings by Weekday") +
guides(fill=FALSE) +
tilt_theme
p7

The above graphs show that most of the job postings are recent and there has been large increase in jobs in 2017 and 2018. January and february are hot months for jobs. Also, the jobs are posted generally on weekdays, mostly on tuesdays and wednesday. This is true as generally employees are completing more work in the first half of weekdays.
Analysis of Job titles
What are most popular job titles?
title <- arrange(as.data.frame(table(amazon$Title)), desc(Freq))
colnames(title) <- c("Title", "Freq")
p8 <- ggplot(data = head(title, 10), aes(Title, Freq, fill = Title)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Top 10 jobs") +
guides(fill=FALSE) +
coord_flip() +
tilt_theme
p8

There are various job postings. Top 10 are shown above. Let us now divide it in different domains and different positions.
# software, game, quality, data, web, security, sale,iot, research
# lead, manager, developer, engineer, consultant, artist, analyst, scientist,
domain <- c("software", "game", "quality", "data", "web", "security", "sale", "research", "iot", "ui")
positions <- c("lead", "leader","manager", "developer", "engineer", "consultant", "artist", "analyst", "scientist")
amazon$Title <- tolower(amazon$Title)
#unique(amazon$Title)
amazon$domain <- NA
amazon$positions <- NA
for(i in domain){
amazon$domain1 <- grepl(i, amazon$Title)
amazon$domain <- ifelse(amazon$domain1 == "TRUE", i, amazon$domain)
}
amazon$domain <- ifelse(amazon$domain == FALSE, "other", amazon$domain)
for(i in positions){
amazon$pos1 <- grepl(i, amazon$Title)
amazon$positions <- ifelse(amazon$pos1 == "TRUE", i, amazon$positions)
}
amazon$positions <- ifelse(is.na(amazon$positions), "other", amazon$positions)
amazon <- subset(amazon, select = -c(domain1, pos1))
pos <- as.data.frame(table(amazon$positions))
colnames(pos) <- c("position", "Freq")
p9 <- ggplot(data = pos, aes(position, Freq, fill = position)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Top 10 domains") +
guides(fill=FALSE) +
coord_flip()
p9

dom <- as.data.frame(table(amazon$domain))
colnames(dom) <- c("domain", "Freq")
p9 <- ggplot(data = dom, aes(domain, Freq, fill = domain)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Top 10 domains") +
guides(fill=FALSE) +
coord_flip()
p9

What are minimum educational qualifications?
amazon$education <- NA
degree_list = c("ba", "bs", "b.tech","bachelor", "phd","ms","master", "mba","m.tech")
amazon$`BASIC QUALIFICATIONS` <- tolower(amazon$`BASIC QUALIFICATIONS`)
for(i in degree_list){
amazon$deg1 <- grepl(i, amazon$`BASIC QUALIFICATIONS`)
amazon$education <- ifelse(amazon$deg1 == "TRUE", i, amazon$education)
}
amazon$education <- ifelse(is.na(amazon$education), "other", amazon$education)
amazon <- subset(amazon, select = -c(deg1))
edu <- as.data.frame(table(amazon$education))
colnames(edu) <- c("Education", "Freq")
p10 <- ggplot(data = edu, aes(Education, Freq, fill = Education)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Jobs based on degrees") +
guides(fill=FALSE) +
coord_flip()
p10

Basic Qualifications generally requires Masters degree.
Which jobs require which type of degrees?


What languages are in demand?
list_of_occurence <- c()
languages <- c('swift','matlab','mongodb','hadoop','cosmos', 'mysql','spark', 'pig', 'python', 'java.', 'java,','c[++]', 'php', 'javascript', 'objective c', 'ruby', 'perl','c ','c#', ' r,')
amazon$`PREFERRED QUALIFICATIONS` <- tolower(amazon$`PREFERRED QUALIFICATIONS`)
for(i in languages){
amazon$dummy <- str_count(amazon$`PREFERRED QUALIFICATIONS`, i)
list_of_occurence <- c(list_of_occurence, sum(amazon$dummy, na.rm = TRUE))
}
list_of_occurence
[1] 26 9 16 164 1 50 128 20 378 1080 392 504 34 348 79 237 188 630 139 7
lan <- data.frame(cbind(languages, as.numeric(list_of_occurence)))
p15 <- ggplot(data = lan, aes(languages, list_of_occurence, fill = languages)) +
geom_bar(stat = "identity") +
geom_text(aes(label=list_of_occurence), color="black", size=3) +
ggtitle("Languages in job description") +
guides(fill=FALSE) +
coord_flip()
p15

Java, C, C++ and python are popular on-demand languages in jobs.
How many years of experience is required?
amazon$dummy <- str_extract(amazon$`BASIC QUALIFICATIONS`, '([0-9]+) year')
amazon$dummy <- ifelse(is.na(amazon$dummy), "0 year", amazon$dummy)
split_year <- function(var){
return(as.numeric(unlist(str_split(var, " "))[1]))
}
amazon$experience <- sapply(amazon$dummy, split_year)
Let’s see the experience, excluding 0 year experience.
exp <- as.data.frame(table(amazon$experience))
colnames(exp) <- c("Experience", "Freq")
p16 <- ggplot(data = filter(exp, exp$Experience != 0), aes(Experience, Freq, fill = Experience)) +
geom_bar(stat = "identity") +
geom_text(aes(label=Freq), color="black", size=3) +
ggtitle("Experience needed") +
guides(fill=FALSE) +
coord_flip()
p16



Word Clouds of Qualifications and Job description
library(wordcloud)
library(SnowballC)
library(RColorBrewer)
library(tm)
texts <- amazon$`PREFERRED QUALIFICATIONS`
#texts <- iconv(texts, to = "utf-8")
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
#corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, removeWords, c("00b7","and", "this", "there"))
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
d <- d[-which(d$word %in% c("00b7","and","this","that")),]
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
max.words=200, random.order=FALSE, rot.per=0.35,
colors=brewer.pal(8, "Dark2"))
title("Preferred Qualifications Word Cloud")

texts <- amazon$`BASIC QUALIFICATIONS`
#texts <- iconv(texts, to = "utf-8")
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
#corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, removeWords, c("00b7","and", "this", "there"))
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
d <- d[-which(d$word %in% c("00b7","and","this","that")),]
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
max.words=200, random.order=FALSE, rot.per=0.35,
colors=brewer.pal(8, "Dark2"))
title("Basic Qualifications Word Cloud")


texts <- amazon$Title
#texts <- iconv(texts, to = "utf-8")
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
#corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, removeWords, c("00b7","and", "this", "there", "you", "will"))
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
#d <- d[-which(d$word %in% c("00b7","and","this","that", "you", "will")),]
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
max.words=200, random.order=FALSE, rot.per=0.35,
colors=brewer.pal(8, "Dark2"))
title("Job Title Word Cloud")

LS0tCnRpdGxlOiAiQW1hem9uIEpvYnMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkxldCdzIGNoZWNrIG91dCB0aGUgZGF0YSEKCmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQphbWF6b24gPC0gcmVhZF9jc3YoImFtYXpvbl9qb2JzX2RhdGFzZXQuY3N2IikKaGVhZChhbWF6b24pCmBgYAoKUXVlc3Rpb25zIHRoYXQgd2UgY2FuIGZvY3VzIG9uOgogIC0gV2hhdCBhcmUgdGhlIHBvcHVsYXIgbG9jYXRpb25zIG9mIGpvYiBvcGVuaW5ncz8KICAtIEFyZSB0aGVyZSBjZXJ0YWluIG1vbnRocyB3aGVuIGpvYiBvcGVuaW5nIGFyZSBtb3JlPyAKICAgIC0gSG93IG1hbnkgam9icyBhcmUgcG9zdGVkIGV2ZXJ5IHllYXI/CiAgICAtIEhvdyBtYW55IGpvYnMgYXJlIHBvc3RlZCBldmVyeSBtb250aD8KICAtIFdoYXQgYXJlIG1vc3QgcG9wdWxhciBqb2IgdGl0bGVzPwogIC0gV2hhdCBhcmUgbWluaW11bSBlZHVjYXRpb25hbCBxdWFsaWZpY2F0aW9ucz8KICAgIC0gV2hpY2ggam9iIHJlcXVpcmVzIGhpZ2hlciBkZWdyZWU/CiAgLSBXaGF0IGxhbmd1YWdlcyBhcmUgcmVxdWlyZWQgZm9yIGpvYnM/CiAgLSBIb3cgbWFueSB5ZWFycyBvZiBleHBlcmllbmNlIGlzIHJlcXVpcmVkPwogICAgLSBXaGljaCBqb2IgY2F0ZWdvcmllcyByZXF1aXJlIG1vcmUgZXhwZXJpZW5jZT8KICAtIFdvcmQgY2xvdWRzIG9mIHByZWZlcnJlZCBxdWFsaWZpY2F0aW9ucwogIC0gV29yZCBjbG91ZHMgb2YgQmFzaWMgUXVhbGlmaWNhdGlvbnMKICAtIFdvcmQgY2xvdWRzIG9mIEpPYiBkZXNjcmlwdGlvbgoKYGBge3J9CmRpbShhbWF6b24pCmBgYApgYGB7cn0KdW5pcXVlKGFtYXpvbiRQb3N0aW5nX2RhdGUpWzE6MjBdCmBgYAoKV2Ugc2VlIHRoYXQgaW4gc29tZSBkYXRlcywgdGhlcmUgYXJlIG11bHRpcGxlIHNwYWNlcyBiZXR3ZWVuIG1vbnRoIGFuZCBkYXkuIExldCdzIHNwbGl0IGl0IHRvIHllYXIgbW9udGggYW5kIGRheS4KCmBgYHtyfQpsaWJyYXJ5KHN0cmluZ3IpCmFtYXpvbiRwb3N0aW5nX21vbnRoIDwtIHN0cl9leHRyYWN0KGFtYXpvbiRQb3N0aW5nX2RhdGUgLCAiKFtBLVphLXpdKykiKQphbWF6b24kcG9zdGluZ19kYXkgPC0gc3RyX2V4dHJhY3QoYW1hem9uJFBvc3RpbmdfZGF0ZSAsICIoWzAtOV0rKSIpCmFtYXpvbiRwb3N0aW5nX3llYXIgPC0gc3RyX2V4dHJhY3QoYW1hem9uJFBvc3RpbmdfZGF0ZSwgIihbMC05XXs0fSkiKQpgYGAKCmBgYHtyfQp1bmlxdWUoYW1hem9uJHBvc3RpbmdfbW9udGgpCnVuaXF1ZShhbWF6b24kcG9zdGluZ19kYXkpCnVuaXF1ZShhbWF6b24kcG9zdGluZ195ZWFyKQpgYGAKTGV0J3MgYWxzbyBleHRyYWN0IHRoZSBjb3VudHJpZXMgZnJvbSBsb2NhdGlvbiBjb2x1bW4uCgpgYGB7cn0KYW1hem9uJGNvdW50cnkgPC0gc3RyX2V4dHJhY3QoYW1hem9uJGxvY2F0aW9uLCAiW0EtWmEtel0rIikKdW5pcXVlKGFtYXpvbiRjb3VudHJ5KQpgYGAKCmBgYHtyfQp1bmlxdWUoYW1hem9uJGxvY2F0aW9uKQpgYGAKCmBgYHtyfQphbWF6b24kY2l0eSA8LSB3b3JkKGFtYXpvbiRsb2NhdGlvbiwgLTEpCnVuaXF1ZShhbWF6b24kY2l0eSkKYGBgCgpMZXQgdXMgY29ycmVjdCB0aGUgY2l0eSBuYW1lcyB0aGF0IGhhdmUgbXVsdGlwbGUgd29yZHMuCmBgYHtyfQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiQWx0byIsIHJlcGxhY2VtZW50ID0gIkVhc3QgUGFsbyBBbHRvIiwgYW1hem9uJGNpdHkpCmFtYXpvbiRjaXR5IDwtIGdzdWIocGF0dGVybiA9ICJJYTxVKzAxNUY+aSIsIHJlcGxhY2VtZW50ID0gIklhc2kiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIk1vbmljYSIsIHJlcGxhY2VtZW50ID0gIlNhbnRhIE1vbmljYSIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiRnJhbmNpc2NvIiwgcmVwbGFjZW1lbnQgPSAiU2FuIEZyYW5jaXNjbyIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiV3JvY2xhd3NraWUiLCByZXBsYWNlbWVudCA9ICJCaWVsYW55IFdyb2NsYXdza2llIiwgYW1hem9uJGNpdHkpCmFtYXpvbiRjaXR5IDwtIGdzdWIocGF0dGVybiA9ICJEaWVnbyIsIHJlcGxhY2VtZW50ID0gIlNhbiBEaWVnbyIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiQmFyYmFyYSIsIHJlcGxhY2VtZW50ID0gIlNhbnRhIEJhcmJhcmEiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIllvcmsiLCByZXBsYWNlbWVudCA9ICJOZXcgWW9yayIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiVG93biIsIHJlcGxhY2VtZW50ID0gIkNhcGUgVG93biIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiQ3J1eiIsIHJlcGxhY2VtZW50ID0gIlNhbnRhIENydXoiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIk9iaXNwbyIsIHJlcGxhY2VtZW50ID0gIlNhbiBMdWlzIE9iaXNwbyIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiUGF1bG8iLCByZXBsYWNlbWVudCA9ICJTYW8gUGF1bG8iLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIkhhc2hhcm9uIiwgcmVwbGFjZW1lbnQgPSAiSG9kIEhhc2hhcm9uIiwgYW1hem9uJGNpdHkpCmFtYXpvbiRjaXR5IDwtIGdzdWIocGF0dGVybiA9ICJJTCwiLCByZXBsYWNlbWVudCA9ICJIb2QgSGFzaGFyb24iLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIk9uLCIsIHJlcGxhY2VtZW50ID0gIk90dGF3YSIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBnc3ViKHBhdHRlcm4gPSAiSm9zZSIsIHJlcGxhY2VtZW50ID0gIlNhbiBKb3NlIiwgYW1hem9uJGNpdHkpCmFtYXpvbiRjaXR5IDwtIGdzdWIocGF0dGVybiA9ICJDQSwiLCByZXBsYWNlbWVudCA9ICJPdHRhd2EiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gZ3N1YihwYXR0ZXJuID0gIlZlZ2FzIiwgcmVwbGFjZW1lbnQgPSAiTGFzIFZlZ2FzIiwgYW1hem9uJGNpdHkpCmBgYAoKVGhlIHdvcmQgIkNpdHkiIGhhcyBiZWVuIHVzZWQgd2l0aCB0aHJlZSBkaWZmZXJlbnQgY2l0aWVzLCBzbyBpbmNsdWRlIHRoZW0uCgpgYGB7cn0KYW1hem9uJGNpdHkgPC0gaWZlbHNlKGFtYXpvbiRsb2NhdGlvbiA9PSAiVVMsIENBLCBGb3N0ZXIgQ2l0eSIsICJGb3N0ZXIgQ2l0eSIsIGFtYXpvbiRjaXR5KQphbWF6b24kY2l0eSA8LSBpZmVsc2UoYW1hem9uJGxvY2F0aW9uID09ICJNWCwgRU1FWCwgTWV4aWNvIENpdHkiLCAiTWV4aWNvIENpdHkiLCBhbWF6b24kY2l0eSkKYW1hem9uJGNpdHkgPC0gaWZlbHNlKGFtYXpvbiRsb2NhdGlvbiA9PSAiVVMsIE5KLCBKZXJzZXkgQ2l0eSIsICJKZXJzZXkgQ2l0eSIsIGFtYXpvbiRjaXR5KQpgYGAKCmBgYHtyfQpoZWFkKGFtYXpvbikKYGBgCgojIFdoYXQgYXJlIG1vc3QgcG9wdWxhciBsb2NhdGlvbnMgb2YgSm9iIE9wZW5pbmdzPwoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxvY2F0aW9uIDwtIGFtYXpvblssIGMoImNvdW50cnkiLCAiY2l0eSIpXQpsb2MxIDwtIGFzLmRhdGEuZnJhbWUodGFibGUobG9jYXRpb24kY2l0eSkpCmNvbG5hbWVzKGxvYzEpIDwtIGMoImNpdHkiLCAiRnJlcSIpCgpsb2MxIDwtIG1lcmdlKGxvYzEsbG9jYXRpb24sYnk9ImNpdHkiKQpsb2MxIDwtIGFycmFuZ2UobG9jMSwgZGVzYyhGcmVxKSkKbG9jMSA8LSBsb2MxICU+JSBkaXN0aW5jdChjaXR5LCAua2VlcF9hbGwgPSBUUlVFKQpsb2MxCmBgYAoKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTMsIGVjaG89RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShSbWlzYykKdGlsdF90aGVtZSA8LSB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGhlYWQobG9jMSwgMTApLCBhZXMoY2l0eSwgRnJlcSwgZmlsbCA9IGNvdW50cnkpKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9RnJlcSksIGNvbG9yPSJibGFjayIsIHNpemU9MykgKwogICAgICBnZ3RpdGxlKCJUb3AgMTAgSm9iIExvY2F0aW9ucyIpICsgCiAgICAgIGNvb3JkX2ZsaXAoKSArCiAgICAgIHRpbHRfdGhlbWUgCnAxCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9MywgZWNobz1GQUxTRX0KcDIgPC0gZ2dwbG90KGRhdGEgPSB0YWlsKGxvYzEsIDUwKSwgYWVzKGNpdHksIEZyZXEsIGZpbGwgPSBjb3VudHJ5KSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiTGFzdCA1MCBKb2IgTG9jYXRpb25zIikgKyAKICAgICAgY29vcmRfZmxpcCgpICsKICAgICAgdGlsdF90aGVtZSAKcDIKYGBgCgpEaXN0cmlidXRpb24gb2YgSm9icyBpbiBhbGwgY291bnRyaWVzIGV4Y2VwdCBVUwpgYGB7cn0KcDMgPC0gZ2dwbG90KGZpbHRlcihsb2MxLGxvYzEkY291bnRyeSE9IlVTIiksIGFlcyh4PWZhY3Rvcihjb3VudHJ5KSwgeT1GcmVxLCBmaWxsID0gZmFjdG9yKGNvdW50cnkpKSkgKyAKICBnZW9tX2JveHBsb3QoKSAKcDMKYGBgCgpEaXN0cmlidXRpb24gb2Ygam9icyBpbiBVUwoKYGBge3J9CnA0IDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGxvYzEsIGxvYzEkY291bnRyeSA9PSAiVVMiKSwgYWVzKGNpdHksIEZyZXEsIGZpbGwgPSBjaXR5KSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiSm9icyBpbiBVUyIpICsgCiAgICAgIGNvb3JkX2ZsaXAoKSArCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUgCnA0CmBgYAoKIyBBbmFseXNpcyBvZiBKb2IgUG9zdGluZyBEYXRlCgojIyBIb3cgbWFueSBqb2JzIGFyZSBwb3N0ZWQgZXZlcnkgeWVhciBhbmQgZXZlcnkgbW9udGg/IElzIHRoZXJlIGEgY2VydGFpbiBwZXJpb2Qgb2YgeWVhciB3aGVuIGpvYnMgYXJlIHBvc3RlZCBtb3JlIGZlcXVlbnRseT8KCmBgYHtyfQoKYW1hem9uJFBvc3RpbmdfZGF0ZSA8LSBwYXN0ZShhbWF6b24kcG9zdGluZ195ZWFyLCBhbWF6b24kcG9zdGluZ19tb250aCwgYW1hem9uJHBvc3RpbmdfZGF5LHNlcD0iLSIpCgphbWF6b24kUG9zdGluZ19kYXRlIDwtIGFzLkRhdGUoc3RycHRpbWUoYW1hem9uJFBvc3RpbmdfZGF0ZSxmb3JtYXQ9IiVZLSViLSVkIikpCiNhbWF6b24kUG9zdGluZ19kYXRlJHpvbmUgPC0gTlVMTAooYW1hem9uJFBvc3RpbmdfZGF0ZVsxOjEwXSkKCiNnZXQgZGF5IG9mIHRoZSB3ZWVrIGJhc2VkIG9uIGRhdGUKZG93IDwtIGZ1bmN0aW9uKHgpIGZvcm1hdChhcy5EYXRlKHgpLCAiJUEiKQphbWF6b24kd2Vla2RheSA8LSBkb3coYW1hem9uJFBvc3RpbmdfZGF0ZSkKYW1hem9uJHdlZWtkYXlbMToyMF0KYGBgCgpgYGB7cn0KcG9zdGluZ19kYXRlIDwtIGFtYXpvblssYygicG9zdGluZ19tb250aCIsICJwb3N0aW5nX3llYXIiLCAid2Vla2RheSIsICJQb3N0aW5nX2RhdGUiKV0KaGVhZChwb3N0aW5nX2RhdGUpCmBgYAoKYGBge3J9CnllYXIgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3N0aW5nX2RhdGUkcG9zdGluZ195ZWFyKSkKY29sbmFtZXMoeWVhcikgPC0gYygiWWVhciIsICJGcmVxIikKcDUgPC0gZ2dwbG90KGRhdGEgPSB5ZWFyLCBhZXMoWWVhciwgRnJlcSwgZmlsbCA9IFllYXIpKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9RnJlcSksIGNvbG9yPSJibGFjayIsIHNpemU9MykgKwogICAgICBnZ3RpdGxlKCJKb2JzIHBvc3RpbmdzIGJ5IFllYXIiKSArIAogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICB0aWx0X3RoZW1lIApwNQpgYGAKCmBgYHtyfQptb24gPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3N0aW5nX2RhdGUkcG9zdGluZ19tb250aCkpCmNvbG5hbWVzKG1vbikgPC0gYygiTW9uIiwgIkZyZXEiKQpsZXYgPSBjKCJKYW51YXJ5IiwgIkZlYnJ1YXJ5IiwgIk1hcmNoIiwgIkFwcmlsIiwgIk1heSIsICJKdW5lIiwgIkp1bHkiLCAiQXVndXN0IiwgIlNlcHRlbWJlciIsICJPY3RvYmVyIiwgIk5vdmVtYmVyIiwgIkRlY2VtYmVyIikKbW9uJE1vbnRoIDwtIGZhY3Rvcihtb24kTW9uLCBsZXYpCiAKcDYgPC0gZ2dwbG90KGRhdGEgPSBtb24sIGFlcyhNb250aCwgRnJlcSwgZmlsbCA9IE1vbnRoKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiSm9icyBwb3N0aW5ncyBieSBNb250aCIpICsgCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIHRpbHRfdGhlbWUgCnA2CmBgYAoKYGBge3J9CmpkYXkgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShwb3N0aW5nX2RhdGUkd2Vla2RheSkpCmNvbG5hbWVzKGpkYXkpIDwtIGMoIndkIiwgIkZyZXEiKQpsZXYgPC0gYygiU3VuZGF5IiwgIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiLCAiU2F0dXJkYXkiKQpqZGF5JHdlZWtkYXkgPC0gZmFjdG9yKGpkYXkkd2QsIGxldikKCnA3IDwtIGdncGxvdChkYXRhID0gamRheSwgYWVzKHdlZWtkYXksIEZyZXEsIGZpbGwgPSB3ZWVrZGF5KSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiSm9icyBwb3N0aW5ncyBieSBXZWVrZGF5IikgKyAKICAgICAgZ3VpZGVzKGZpbGw9RkFMU0UpICsKICAgICAgdGlsdF90aGVtZSAKcDcKYGBgCgpUaGUgYWJvdmUgZ3JhcGhzIHNob3cgdGhhdCBtb3N0IG9mIHRoZSBqb2IgcG9zdGluZ3MgYXJlIHJlY2VudCBhbmQgdGhlcmUgaGFzIGJlZW4gbGFyZ2UgaW5jcmVhc2UgaW4gam9icyBpbiAyMDE3IGFuZCAyMDE4LiBKYW51YXJ5IGFuZCBmZWJydWFyeSBhcmUgaG90IG1vbnRocyBmb3Igam9icy4gQWxzbywgdGhlIGpvYnMgYXJlIHBvc3RlZCBnZW5lcmFsbHkgb24gd2Vla2RheXMsIG1vc3RseSBvbiB0dWVzZGF5cyBhbmQgd2VkbmVzZGF5LiBUaGlzIGlzIHRydWUgYXMgZ2VuZXJhbGx5IGVtcGxveWVlcyBhcmUgY29tcGxldGluZyBtb3JlIHdvcmsgaW4gdGhlIGZpcnN0IGhhbGYgb2Ygd2Vla2RheXMuIAoKIyBBbmFseXNpcyBvZiBKb2IgdGl0bGVzCgojIyBXaGF0IGFyZSBtb3N0IHBvcHVsYXIgam9iIHRpdGxlcz8KCmBgYHtyfQp0aXRsZSA8LSBhcnJhbmdlKGFzLmRhdGEuZnJhbWUodGFibGUoYW1hem9uJFRpdGxlKSksIGRlc2MoRnJlcSkpCmNvbG5hbWVzKHRpdGxlKSA8LSBjKCJUaXRsZSIsICJGcmVxIikKcDggPC0gZ2dwbG90KGRhdGEgPSBoZWFkKHRpdGxlLCAxMCksIGFlcyhUaXRsZSwgRnJlcSwgZmlsbCA9IFRpdGxlKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiVG9wIDEwIGpvYnMiKSArIAogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICBjb29yZF9mbGlwKCkgKwogICAgICB0aWx0X3RoZW1lIApwOApgYGAKClRoZXJlIGFyZSB2YXJpb3VzIGpvYiBwb3N0aW5ncy4gVG9wIDEwIGFyZSBzaG93biBhYm92ZS4gTGV0IHVzIG5vdyBkaXZpZGUgaXQgaW4gZGlmZmVyZW50IGRvbWFpbnMgYW5kIGRpZmZlcmVudCBwb3NpdGlvbnMuCmBgYHtyfQoKIyBzb2Z0d2FyZSwgZ2FtZSwgcXVhbGl0eSwgZGF0YSwgd2ViLCBzZWN1cml0eSwgc2FsZSxpb3QsIHJlc2VhcmNoCiMgbGVhZCwgbWFuYWdlciwgZGV2ZWxvcGVyLCBlbmdpbmVlciwgY29uc3VsdGFudCwgYXJ0aXN0LCBhbmFseXN0LCBzY2llbnRpc3QsCmRvbWFpbiA8LSBjKCJzb2Z0d2FyZSIsICJnYW1lIiwgInF1YWxpdHkiLCAiZGF0YSIsICJ3ZWIiLCAic2VjdXJpdHkiLCAic2FsZSIsICJyZXNlYXJjaCIsICJpb3QiLCAidWkiKQpwb3NpdGlvbnMgPC0gYygibGVhZCIsICJsZWFkZXIiLCJtYW5hZ2VyIiwgImRldmVsb3BlciIsICJlbmdpbmVlciIsICJjb25zdWx0YW50IiwgImFydGlzdCIsICJhbmFseXN0IiwgInNjaWVudGlzdCIpCmFtYXpvbiRUaXRsZSA8LSB0b2xvd2VyKGFtYXpvbiRUaXRsZSkKI3VuaXF1ZShhbWF6b24kVGl0bGUpCmFtYXpvbiRkb21haW4gPC0gTkEKYW1hem9uJHBvc2l0aW9ucyA8LSBOQQoKYGBgCgoKCmBgYHtyfQpmb3IoaSBpbiBkb21haW4pewphbWF6b24kZG9tYWluMSA8LSBncmVwbChpLCBhbWF6b24kVGl0bGUpCmFtYXpvbiRkb21haW4gPC0gaWZlbHNlKGFtYXpvbiRkb21haW4xID09ICJUUlVFIiwgaSwgYW1hem9uJGRvbWFpbikKfQphbWF6b24kZG9tYWluIDwtIGlmZWxzZShhbWF6b24kZG9tYWluID09IEZBTFNFLCAib3RoZXIiLCBhbWF6b24kZG9tYWluKQoKZm9yKGkgaW4gcG9zaXRpb25zKXsKICBhbWF6b24kcG9zMSA8LSBncmVwbChpLCBhbWF6b24kVGl0bGUpCiAgYW1hem9uJHBvc2l0aW9ucyA8LSBpZmVsc2UoYW1hem9uJHBvczEgPT0gIlRSVUUiLCBpLCBhbWF6b24kcG9zaXRpb25zKQp9CmFtYXpvbiRwb3NpdGlvbnMgPC0gaWZlbHNlKGlzLm5hKGFtYXpvbiRwb3NpdGlvbnMpLCAib3RoZXIiLCBhbWF6b24kcG9zaXRpb25zKQphbWF6b24gPC0gc3Vic2V0KGFtYXpvbiwgc2VsZWN0ID0gLWMoZG9tYWluMSwgcG9zMSkpCgpgYGAKCmBgYHtyfQpwb3MgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kcG9zaXRpb25zKSkKY29sbmFtZXMocG9zKSA8LSBjKCJwb3NpdGlvbiIsICJGcmVxIikKcDkgPC0gZ2dwbG90KGRhdGEgPSBwb3MsIGFlcyhwb3NpdGlvbiwgRnJlcSwgZmlsbCA9IHBvc2l0aW9uKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpLCBjb2xvcj0iYmxhY2siLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiVG9wIDEwIGRvbWFpbnMiKSArIAogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICBjb29yZF9mbGlwKCkgCnA5CmBgYAoKYGBge3J9CmRvbSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGFtYXpvbiRkb21haW4pKQpjb2xuYW1lcyhkb20pIDwtIGMoImRvbWFpbiIsICJGcmVxIikKcDkgPC0gZ2dwbG90KGRhdGEgPSBkb20sIGFlcyhkb21haW4sIEZyZXEsIGZpbGwgPSBkb21haW4pKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9RnJlcSksIGNvbG9yPSJibGFjayIsIHNpemU9MykgKwogICAgICBnZ3RpdGxlKCJUb3AgMTAgZG9tYWlucyIpICsgCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIGNvb3JkX2ZsaXAoKSAKcDkKYGBgCgojIFdoYXQgYXJlIG1pbmltdW0gZWR1Y2F0aW9uYWwgcXVhbGlmaWNhdGlvbnM/CgpgYGB7cn0KYW1hem9uJGVkdWNhdGlvbiA8LSBOQQpkZWdyZWVfbGlzdCA9IGMoImJhIiwgImJzIiwgImIudGVjaCIsImJhY2hlbG9yIiwgInBoZCIsIm1zIiwibWFzdGVyIiwgIm1iYSIsIm0udGVjaCIpCmFtYXpvbiRgQkFTSUMgUVVBTElGSUNBVElPTlNgIDwtIHRvbG93ZXIoYW1hem9uJGBCQVNJQyBRVUFMSUZJQ0FUSU9OU2ApCgpmb3IoaSBpbiBkZWdyZWVfbGlzdCl7CiAgYW1hem9uJGRlZzEgPC0gZ3JlcGwoaSwgYW1hem9uJGBCQVNJQyBRVUFMSUZJQ0FUSU9OU2ApCiAgYW1hem9uJGVkdWNhdGlvbiA8LSBpZmVsc2UoYW1hem9uJGRlZzEgPT0gIlRSVUUiLCBpLCBhbWF6b24kZWR1Y2F0aW9uKQp9CmFtYXpvbiRlZHVjYXRpb24gPC0gaWZlbHNlKGlzLm5hKGFtYXpvbiRlZHVjYXRpb24pLCAib3RoZXIiLCBhbWF6b24kZWR1Y2F0aW9uKQphbWF6b24gPC0gc3Vic2V0KGFtYXpvbiwgc2VsZWN0ID0gLWMoZGVnMSkpCgpgYGAKCmBgYHtyfQplZHUgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kZWR1Y2F0aW9uKSkKY29sbmFtZXMoZWR1KSA8LSBjKCJFZHVjYXRpb24iLCAiRnJlcSIpCnAxMCA8LSBnZ3Bsb3QoZGF0YSA9IGVkdSwgYWVzKEVkdWNhdGlvbiwgRnJlcSwgZmlsbCA9IEVkdWNhdGlvbikpICsKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1GcmVxKSwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zKSArCiAgICAgIGdndGl0bGUoIkpvYnMgYmFzZWQgb24gZGVncmVlcyIpICsgCiAgICAgIGd1aWRlcyhmaWxsPUZBTFNFKSArCiAgICAgIGNvb3JkX2ZsaXAoKSAKcDEwCmBgYAoKQmFzaWMgUXVhbGlmaWNhdGlvbnMgZ2VuZXJhbGx5IHJlcXVpcmVzIE1hc3RlcnMgZGVncmVlLgoKIyMgV2hpY2ggam9icyByZXF1aXJlIHdoaWNoIHR5cGUgb2YgZGVncmVlcz8KCgpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBlY2hvPUZBTFNFfQpjb3VudHMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kZG9tYWluLCBhbWF6b24kZWR1Y2F0aW9uKSkKY29sbmFtZXMoY291bnRzKSA8LSBjKCJEb21haW4iLCAiRWR1Y2F0aW9uIiwgIkZyZXEiKQpwMTEgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoY291bnRzLCBjb3VudHMkRG9tYWluICE9ICJzb2Z0d2FyZSIpLCBhZXMoRG9tYWluLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEVkdWNhdGlvbiksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJEb21haW4gZGlzdHJpYnV0aW9uIGJhc2VkIG9uIEVkdWNhdGlvbiIpIAoKcDEyIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGNvdW50cywgY291bnRzJERvbWFpbiA9PSAic29mdHdhcmUiKSwgYWVzKERvbWFpbiwgRnJlcSkpICsKICAgICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBFZHVjYXRpb24pLCBwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2d0aXRsZSgiRG9tYWluIGRpc3RyaWJ1dGlvbiBiYXNlZCBvbiBFZHVjYXRpb24iKSAKbXVsdGlwbG90KHAxMSwgcDEyKQpgYGAKCmBgYHtyIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGVjaG89RkFMU0V9CmNvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGFtYXpvbiRwb3NpdGlvbnMsIGFtYXpvbiRlZHVjYXRpb24pKQpjb2xuYW1lcyhjb3VudHMpIDwtIGMoIlBvc2l0aW9ucyIsICJFZHVjYXRpb24iLCAiRnJlcSIpCnAxMyA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRQb3NpdGlvbnMgIT0gImVuZ2luZWVyIiksIGFlcyhQb3NpdGlvbnMsIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKGFlcyhmaWxsID0gRWR1Y2F0aW9uKSwgcG9zaXRpb24gPSAiZG9kZ2UiLHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdndGl0bGUoIlBvc2l0aW9ucyBkaXN0cmlidXRpb24gYmFzZWQgb24gRWR1Y2F0aW9uIikgCgpwMTQgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoY291bnRzLCBjb3VudHMkUG9zaXRpb25zID09ICJlbmdpbmVlciIpLCBhZXMoUG9zaXRpb25zLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEVkdWNhdGlvbiksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJQb3NpdGlvbnMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIEVkdWNhdGlvbiIpIAptdWx0aXBsb3QocDEzLCBwMTQpCmBgYAoKIyBXaGF0IGxhbmd1YWdlcyBhcmUgaW4gZGVtYW5kPwoKYGBge3J9Cmxpc3Rfb2Zfb2NjdXJlbmNlIDwtIGMoKQpsYW5ndWFnZXMgPC0gYygnc3dpZnQnLCdtYXRsYWInLCdtb25nb2RiJywnaGFkb29wJywnY29zbW9zJywgJ215c3FsJywnc3BhcmsnLCAncGlnJywgJ3B5dGhvbicsICdqYXZhLicsICdqYXZhLCcsJ2NbKytdJywgJ3BocCcsICdqYXZhc2NyaXB0JywgJ29iamVjdGl2ZSBjJywgJ3J1YnknLCAncGVybCcsJ2MgJywnYyMnLCAnIHIsJykKYW1hem9uJGBQUkVGRVJSRUQgUVVBTElGSUNBVElPTlNgIDwtIHRvbG93ZXIoYW1hem9uJGBQUkVGRVJSRUQgUVVBTElGSUNBVElPTlNgKQoKZm9yKGkgaW4gbGFuZ3VhZ2VzKXsKICBhbWF6b24kZHVtbXkgPC0gc3RyX2NvdW50KGFtYXpvbiRgUFJFRkVSUkVEIFFVQUxJRklDQVRJT05TYCwgaSkKICBsaXN0X29mX29jY3VyZW5jZSA8LSBjKGxpc3Rfb2Zfb2NjdXJlbmNlLCBzdW0oYW1hem9uJGR1bW15LCBuYS5ybSA9IFRSVUUpKQp9Cmxpc3Rfb2Zfb2NjdXJlbmNlCmBgYAoKYGBge3J9CmxhbiA8LSBkYXRhLmZyYW1lKGNiaW5kKGxhbmd1YWdlcywgYXMubnVtZXJpYyhsaXN0X29mX29jY3VyZW5jZSkpKQpwMTUgPC0gZ2dwbG90KGRhdGEgPSBsYW4sIGFlcyhsYW5ndWFnZXMsIGxpc3Rfb2Zfb2NjdXJlbmNlLCBmaWxsID0gbGFuZ3VhZ2VzKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPWxpc3Rfb2Zfb2NjdXJlbmNlKSwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zKSArCiAgICAgIGdndGl0bGUoIkxhbmd1YWdlcyBpbiBqb2IgZGVzY3JpcHRpb24iKSArIAogICAgICBndWlkZXMoZmlsbD1GQUxTRSkgKwogICAgICBjb29yZF9mbGlwKCkgCnAxNQpgYGAKCkphdmEsIEMsIEMrKyBhbmQgcHl0aG9uIGFyZSBwb3B1bGFyIG9uLWRlbWFuZCBsYW5ndWFnZXMgaW4gam9icy4KCgojIEhvdyBtYW55IHllYXJzIG9mIGV4cGVyaWVuY2UgaXMgcmVxdWlyZWQ/CgpgYGB7cn0KYW1hem9uJGR1bW15IDwtIHN0cl9leHRyYWN0KGFtYXpvbiRgQkFTSUMgUVVBTElGSUNBVElPTlNgLCAnKFswLTldKykgeWVhcicpCmFtYXpvbiRkdW1teSA8LSBpZmVsc2UoaXMubmEoYW1hem9uJGR1bW15KSwgIjAgeWVhciIsIGFtYXpvbiRkdW1teSkKCnNwbGl0X3llYXIgPC0gZnVuY3Rpb24odmFyKXsKIHJldHVybihhcy5udW1lcmljKHVubGlzdChzdHJfc3BsaXQodmFyLCAiICIpKVsxXSkpCn0KYW1hem9uJGV4cGVyaWVuY2UgPC0gc2FwcGx5KGFtYXpvbiRkdW1teSwgc3BsaXRfeWVhcikKCmBgYAoKTGV0J3Mgc2VlIHRoZSBleHBlcmllbmNlLCBleGNsdWRpbmcgMCB5ZWFyIGV4cGVyaWVuY2UuCmBgYHtyfQpleHAgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kZXhwZXJpZW5jZSkpCmNvbG5hbWVzKGV4cCkgPC0gYygiRXhwZXJpZW5jZSIsICJGcmVxIikKcDE2IDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGV4cCwgZXhwJEV4cGVyaWVuY2UgIT0gMCksIGFlcyhFeHBlcmllbmNlLCBGcmVxLCBmaWxsID0gRXhwZXJpZW5jZSkpICsKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1GcmVxKSwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zKSArCiAgICAgIGdndGl0bGUoIkV4cGVyaWVuY2UgbmVlZGVkIikgKyAKICAgICAgZ3VpZGVzKGZpbGw9RkFMU0UpICsKICAgICAgY29vcmRfZmxpcCgpIApwMTYKYGBgCgpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBlY2hvPUZBTFNFfQpjb3VudHMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbWF6b24kcG9zaXRpb25zLCBhbWF6b24kZXhwZXJpZW5jZSkpCmNvbG5hbWVzKGNvdW50cykgPC0gYygiUG9zaXRpb25zIiwgIkV4cGVyaWVuY2UiLCAiRnJlcSIpCnAxNyA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRFeHBlcmllbmNlICE9IDAgJiBjb3VudHMkUG9zaXRpb25zICE9ICJlbmdpbmVlciIpLCBhZXMoUG9zaXRpb25zLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEV4cGVyaWVuY2UpLCBwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2d0aXRsZSgiUG9zaXRpb25zIGRpc3RyaWJ1dGlvbiBiYXNlZCBvbiBFeHBlcmllbmNlIGZvciBwb3NpdGlvbnMgZXhjbHVkaW5nIGVuZ2lubmVyIikgCnAxOCA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRFeHBlcmllbmNlID09IDAgJiBjb3VudHMkUG9zaXRpb25zICE9ICJlbmdpbmVlciIpLCBhZXMoUG9zaXRpb25zLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEV4cGVyaWVuY2UpLCBwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2d0aXRsZSgiUG9zaXRpb25zIHdoZXJlIEV4cGVyaWVuY2UgaXMgbm90IGRlZmluZWQgZXhjbHVkaW5nIGVuZ2luZWVyIikgCnAxOSA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRQb3NpdGlvbnMgPT0gImVuZ2luZWVyIiksIGFlcyhQb3NpdGlvbnMsIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKGFlcyhmaWxsID0gRXhwZXJpZW5jZSksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJFbmdpbmVlciBQb3NpdGlvbnMgZGlzdHJpYnV0aW9uIGJhc2VkIG9uIEV4cGVyaWVuY2UiKSAKcDIwIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGNvdW50cywgY291bnRzJEV4cGVyaWVuY2UgIT0gMCAmIGNvdW50cyRQb3NpdGlvbnMgPT0gImVuZ2luZWVyIiksIGFlcyhQb3NpdGlvbnMsIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKGFlcyhmaWxsID0gRXhwZXJpZW5jZSksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJFbmdpbmVlciBQb3NpdGlvbnMgd2hlcmUgRXhwZXJpZW5jZSBpcyBub3QgemVybyIpIAptdWx0aXBsb3QocDE3LCBwMTgsIHAxOSwgcDIwLCBsYXlvdXQgPSBtYXRyaXgoYygxLDIsMyw0KSwgbnJvdz0yLCBieXJvdz1UUlVFKSkKCmBgYAoKYGBge3IgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZWNobz1GQUxTRX0KY291bnRzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoYW1hem9uJGRvbWFpbiwgYW1hem9uJGV4cGVyaWVuY2UpKQpjb2xuYW1lcyhjb3VudHMpIDwtIGMoIkRvbWFpbiIsICJFeHBlcmllbmNlIiwgIkZyZXEiKQpwMjEgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoY291bnRzLCBjb3VudHMkRXhwZXJpZW5jZSAhPSAwICYgY291bnRzJERvbWFpbiAhPSAic29mdHdhcmUiKSwgYWVzKERvbWFpbiwgRnJlcSkpICsKICAgICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBFeHBlcmllbmNlKSwgcG9zaXRpb24gPSAiZG9kZ2UiLHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdndGl0bGUoIkRvbWFpbiBkaXN0cmlidXRpb24gYmFzZWQgb24gRXhwZXJpZW5jZSBmb3IgZG9tYWluIGV4Y2x1ZGluZyBzb2Z0d2FyZSIpIAoKcDIyIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGNvdW50cywgY291bnRzJEV4cGVyaWVuY2UgPT0gMCAmIGNvdW50cyREb21haW4gIT0gInNvZnR3YXJlIiksIGFlcyhEb21haW4sIEZyZXEpKSArCiAgICAgIGdlb21fYmFyKGFlcyhmaWxsID0gRXhwZXJpZW5jZSksIHBvc2l0aW9uID0gImRvZGdlIixzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZ3RpdGxlKCJEb21haW4gd2hlcmUgRXhwZXJpZW5jZSBpcyBub3QgZGVmaW5lZCBmb3IgZG9tYWluIGV4Y2x1ZGluZyBzb2Z0d2FyZSIpIAoKcDIzIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKGNvdW50cywgY291bnRzJERvbWFpbiA9PSAic29mdHdhcmUiKSwgYWVzKERvbWFpbiwgRnJlcSkpICsKICAgICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBFeHBlcmllbmNlKSwgcG9zaXRpb24gPSAiZG9kZ2UiLHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdndGl0bGUoIkRvbWFpbiBkaXN0cmlidXRpb24gYmFzZWQgb24gRXhwZXJpZW5jZSBmb3Igc29mdHdhcmUiKSAKCnAyNCA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihjb3VudHMsIGNvdW50cyRFeHBlcmllbmNlICE9IDAgJiBjb3VudHMkRG9tYWluID09ICJzb2Z0d2FyZSIpLCBhZXMoRG9tYWluLCBGcmVxKSkgKwogICAgICBnZW9tX2JhcihhZXMoZmlsbCA9IEV4cGVyaWVuY2UpLCBwb3NpdGlvbiA9ICJkb2RnZSIsc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2d0aXRsZSgiRG9tYWluIHdoZXJlIEV4cGVyaWVuY2UgaXMgbm90IHplcm8gZm9yIHNvZnR3YXJlIikgCgptdWx0aXBsb3QocDIxLCBwMjIsIHAyMywgcDI0LCBsYXlvdXQgPSBtYXRyaXgoYygxLDIsMyw0KSwgbnJvdz0yLCBieXJvdz1UUlVFKSkKYGBgCgojIFdvcmQgQ2xvdWRzIG9mIFF1YWxpZmljYXRpb25zIGFuZCBKb2IgZGVzY3JpcHRpb24KCmBgYHtyfQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeShTbm93YmFsbEMpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHRtKQp0ZXh0cyA8LSBhbWF6b24kYFBSRUZFUlJFRCBRVUFMSUZJQ0FUSU9OU2AKI3RleHRzIDwtIGljb252KHRleHRzLCB0byA9ICJ1dGYtOCIpCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHRleHRzKSkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIFBsYWluVGV4dERvY3VtZW50KQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlUHVuY3R1YXRpb24pCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCdlbmdsaXNoJykpCiNjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgc3RlbURvY3VtZW50KQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIGMoIjAwYjciLCJhbmQiLCAidGhpcyIsICJ0aGVyZSIpKSAKY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzKSkKZHRtIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXMpCm0gPC0gYXMubWF0cml4KGR0bSkKdiA8LSBzb3J0KHJvd1N1bXMobSksZGVjcmVhc2luZz1UUlVFKQpkIDwtIGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHYpLGZyZXE9dikKaGVhZChkLCAxMCkKZCA8LSBkWy13aGljaChkJHdvcmQgJWluJSBjKCIwMGI3IiwiYW5kIiwidGhpcyIsInRoYXQiKSksXQpzZXQuc2VlZCgxMjM0KQp3b3JkY2xvdWQod29yZHMgPSBkJHdvcmQsIGZyZXEgPSBkJGZyZXEsIG1pbi5mcmVxID0gMSwKICAgICAgICAgIG1heC53b3Jkcz0yMDAsIHJhbmRvbS5vcmRlcj1GQUxTRSwgcm90LnBlcj0wLjM1LCAKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDgsICJEYXJrMiIpKQp0aXRsZSgiUHJlZmVycmVkIFF1YWxpZmljYXRpb25zIFdvcmQgQ2xvdWQiKQpgYGAKCmBgYHtyfQp0ZXh0cyA8LSBhbWF6b24kYEJBU0lDIFFVQUxJRklDQVRJT05TYAojdGV4dHMgPC0gaWNvbnYodGV4dHMsIHRvID0gInV0Zi04IikKY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dHMpKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgUGxhaW5UZXh0RG9jdW1lbnQpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVQdW5jdHVhdGlvbikKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoJ2VuZ2xpc2gnKSkKI2NvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBzdGVtRG9jdW1lbnQpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3JkcywgYygiMDBiNyIsImFuZCIsICJ0aGlzIiwgInRoZXJlIikpIApjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShjb3JwdXMpKQpkdG0gPC0gVGVybURvY3VtZW50TWF0cml4KGNvcnB1cykKbSA8LSBhcy5tYXRyaXgoZHRtKQp2IDwtIHNvcnQocm93U3VtcyhtKSxkZWNyZWFzaW5nPVRSVUUpCmQgPC0gZGF0YS5mcmFtZSh3b3JkID0gbmFtZXModiksZnJlcT12KQpoZWFkKGQsIDEwKQpkIDwtIGRbLXdoaWNoKGQkd29yZCAlaW4lIGMoIjAwYjciLCJhbmQiLCJ0aGlzIiwidGhhdCIpKSxdCnNldC5zZWVkKDEyMzQpCndvcmRjbG91ZCh3b3JkcyA9IGQkd29yZCwgZnJlcSA9IGQkZnJlcSwgbWluLmZyZXEgPSAxLAogICAgICAgICAgbWF4LndvcmRzPTIwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCByb3QucGVyPTAuMzUsIAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOCwgIkRhcmsyIikpCnRpdGxlKCJCYXNpYyBRdWFsaWZpY2F0aW9ucyBXb3JkIENsb3VkIikKYGBgCgpgYGB7ciAgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NSwgZWNobz1GQUxTRX0KdGV4dHMgPC0gYW1hem9uJERFU0NSSVBUSU9OCiN0ZXh0cyA8LSBpY29udih0ZXh0cywgdG8gPSAidXRmLTgiKQpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0cykpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBQbGFpblRleHREb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygnZW5nbGlzaCcpKQojY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHN0ZW1Eb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBjKCIwMGI3IiwiYW5kIiwgInRoaXMiLCAidGhlcmUiLCAieW91IiwgIndpbGwiKSkgCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGNvcnB1cykpCmR0bSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQptIDwtIGFzLm1hdHJpeChkdG0pCnYgPC0gc29ydChyb3dTdW1zKG0pLGRlY3JlYXNpbmc9VFJVRSkKZCA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh2KSxmcmVxPXYpCmhlYWQoZCwgMTApCmQgPC0gZFstd2hpY2goZCR3b3JkICVpbiUgYygiMDBiNyIsImFuZCIsInRoaXMiLCJ0aGF0IiwgInlvdSIsICJ3aWxsIikpLF0Kc2V0LnNlZWQoMTIzNCkKd29yZGNsb3VkKHdvcmRzID0gZCR3b3JkLCBmcmVxID0gZCRmcmVxLCBtaW4uZnJlcSA9IDEsCiAgICAgICAgICBtYXgud29yZHM9MjAwLCByYW5kb20ub3JkZXI9RkFMU0UsIHJvdC5wZXI9MC4zNSwgCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSkKdGl0bGUoIkpvYiBEZXNjcmlwdGlvbiBXb3JkIENsb3VkIikKYGBgCgpgYGB7cn0KdGV4dHMgPC0gYW1hem9uJFRpdGxlCiN0ZXh0cyA8LSBpY29udih0ZXh0cywgdG8gPSAidXRmLTgiKQpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0cykpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBQbGFpblRleHREb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygnZW5nbGlzaCcpKQojY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHN0ZW1Eb2N1bWVudCkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBjKCIwMGI3IiwiYW5kIiwgInRoaXMiLCAidGhlcmUiLCAieW91IiwgIndpbGwiKSkgCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGNvcnB1cykpCmR0bSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQptIDwtIGFzLm1hdHJpeChkdG0pCnYgPC0gc29ydChyb3dTdW1zKG0pLGRlY3JlYXNpbmc9VFJVRSkKZCA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh2KSxmcmVxPXYpCmhlYWQoZCwgMTApCiNkIDwtIGRbLXdoaWNoKGQkd29yZCAlaW4lIGMoIjAwYjciLCJhbmQiLCJ0aGlzIiwidGhhdCIsICJ5b3UiLCAid2lsbCIpKSxdCnNldC5zZWVkKDEyMzQpCndvcmRjbG91ZCh3b3JkcyA9IGQkd29yZCwgZnJlcSA9IGQkZnJlcSwgbWluLmZyZXEgPSAxLAogICAgICAgICAgbWF4LndvcmRzPTIwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCByb3QucGVyPTAuMzUsIAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOCwgIkRhcmsyIikpCnRpdGxlKCJKb2IgVGl0bGUgV29yZCBDbG91ZCIpCmBgYAoKCg==